﻿using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace NPOIExcelExtend
{
    public static class ExcelExtend
    {
        /// <summary>
        /// 读取Excel数据
        /// 读取的第一行会识别为 "头部"
        /// 模型 T 属性要跟第一行"头部"对的上
        /// </summary>
        /// <typeparam name="T">模型 T 属性要跟第一行"头部"对的上</typeparam>
        /// <param name="workBook">工作簿</param>
        /// <param name="fileName">文件名（绝对路径）</param>
        /// <param name="selectSheet">簿名</param>
        /// <param name="startRow">开始读取的行数（读的第一行为头部）</param>
        /// <returns></returns>
        public static IList<T> ReadData<T>(this IWorkbook workBook, string fileName, int selectSheet = 0, int startRow = 0)
        {
            var extension = Path.GetExtension(fileName);
            using (FileStream fs = File.OpenRead(fileName))
            {
                if (extension.Equals(".xls"))
                {
                    //把xls文件中的数据写入wk中
                    workBook = new HSSFWorkbook(fs);
                }
                else
                {
                    //把xlsx文件中的数据写入wk中
                    workBook = new XSSFWorkbook(fs);
                }
            }
            var sheet = workBook.GetSheetAt(selectSheet);
            var row = sheet.GetRow(startRow);
            //列号和头部名称映射，之后可以根据列号获取对应的属性
            var dicCellNumberMapHeadName = new Dictionary<int, string>();
            //头部字段跟属性有效性映射，后面判断属性是否可用再进行赋值
            var dicPropertyMapAvailable = new Dictionary<string, bool>();
            var type = typeof(T);
            for (int i = 0; i < row.LastCellNum; i++)
            {
                var value = row.GetCell(i).ToString();
                dicCellNumberMapHeadName.Add(i, value);
                if (type.GetProperty(value) != null)
                {
                    dicPropertyMapAvailable.Add(value, true);
                }
                else
                {
                    dicPropertyMapAvailable.Add(value, false);
                }
            }

            var result = new List<T>();
            //遍历所有行
            while ((row = sheet.GetRow(++startRow)) != null)
            {
                var t = Activator.CreateInstance<T>();
                for (int i = 0; i < row.LastCellNum; i++)
                {
                    var colName = dicCellNumberMapHeadName[i];
                    var isPropertyAvailable = dicPropertyMapAvailable[colName];
                    //判断属性是否可用，可用再进行赋值
                    if (isPropertyAvailable)
                    {
                        var property = type.GetProperty(colName);

                        var cell = row.GetCell(i);
                        dynamic value;
                        switch (cell.CellType)
                        {
                            case CellType.Blank:
                                value = null;
                                break;
                            case CellType.Boolean:
                                value = cell.BooleanCellValue;
                                break;
                            case CellType.Error:
                                value = cell.ErrorCellValue;
                                break;
                            case CellType.Formula:
                                value = cell.CellFormula;
                                break;
                            case CellType.Numeric:
                                value = cell.NumericCellValue;
                                break;
                            case CellType.String:
                                value = cell.StringCellValue;
                                break;
                            case CellType.Unknown:
                                value = cell.ToString();
                                break;
                            default: value = null;
                                break;
                        }
                        if (value != null)
                        {
                            property.SetValue(t, Convert.ChangeType(value, property.PropertyType), null);
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
                result.Add(t);
            }
            return result;
        }

        /// <summary>
        /// 写入数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="workBook">工作簿</param>
        /// <param name="dataList">数据源</param>
        /// <param name="sheetName">表名称</param>
        /// <returns></returns>
        public static MemoryStream WriteData<T>(this IWorkbook workBook ,IList<T> dataList,string sheetName="sheet1")
        {
            workBook = new HSSFWorkbook();
            var sheet = workBook.CreateSheet(sheetName);
            var properties = typeof(T).GetProperties();
            var stream = new MemoryStream();
            for (int i = 0; i < dataList.Count; i++)
            {
                var row = sheet.CreateRow(i);
                for (int j = 0; j < properties.Count(); j++)
                {
                    var cell = row.CreateCell(j);
                    var value = properties[j].GetValue(dataList[i], null);
                    cell.SetCellValue(value == null ? "" : value.ToString());
                }
            }
            workBook.Write(stream);
            stream.Flush();
            stream.Position = 0;
            return stream;
        }
    }
}
